package com.easylinkin.linkappapi.hcmy.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.easylinkin.linkappapi.common.utils.CommonUtils;
import com.easylinkin.linkappapi.common.utils.RegularExpressionConstant;
import com.easylinkin.linkappapi.hcmy.entity.CarManage;
import com.easylinkin.linkappapi.hcmy.mapper.CarManageMapper;
import com.easylinkin.linkappapi.hcmy.service.CarManageService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelReadUtil;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.meterbilling.service.impl.MeterDeviceConfigServiceImpl;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import com.easylinkin.linkappapi.webcammanage.util.YYSHDateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * class info :
 *
 * @author hongyikang
 * @date 2021/8/17 15:04
 */
@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class CarManageServiceImpl extends ServiceImpl<CarManageMapper, CarManage> implements CarManageService {

    private static final Logger LOGGER = LoggerFactory.getLogger(CarManageServiceImpl.class);

    @Resource
    LinkappUserContextProducer linkappUserContextProducer;

    @Override
    public String add(CarManage carManage) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        carManage.setCreator(linkappUser.getId().toString());
        carManage.setModifier(linkappUser.getId().toString());
        carManage.setTenantId(linkappUser.getTenantId());
        carManage.setCode(carManage.getCode().trim());
        //验证车牌号以及设备是否重复
        QueryWrapper<CarManage> qw = new QueryWrapper<CarManage>();
        qw.eq("tenant_id",linkappUser.getTenantId());
        qw.and(QueryWrapper -> QueryWrapper.eq("code", carManage.getCode()).or().eq("gps_id", carManage.getGpsId()));
        Integer count = baseMapper.selectCount(qw);
        if(count > 0){
            return "车牌号或绑定设备重复";
        }

        baseMapper.add(carManage);
        return null;
    }

    @Override
    public IPage<CarManage> getPage(Page page, CarManage carManage) {
        String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
        carManage.setTenantId(tenantId);
        return baseMapper.getPage(page, carManage);
    }

    @Override
    public CarManage getById(Long id) {
        return baseMapper.getById(id);
    }

    @Override
    public String update(CarManage carManage) {
        //获取租户
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();

        //验证车牌号以及设备是否重复
        QueryWrapper<CarManage> qw = new QueryWrapper<CarManage>();
        qw.ne("id",carManage.getId());
        qw.eq("tenant_id",linkappUser.getTenantId());
        qw.and(QueryWrapper -> QueryWrapper.eq("code", carManage.getCode()).or().eq("gps_id", carManage.getGpsId()));
        Integer count = baseMapper.selectCount(qw);
        if(count > 0){
            return "车牌号或绑定设备重复";
        }

        carManage.setModifier(linkappUser.getId().toString());
        baseMapper.update(carManage);
        return null;
    }

    @Override
    public boolean delById(Long id) {
        int i = baseMapper.delById(id);
        return i > 0 ? true : false;
    }

    @Override
    public void exportData(CarManage carManage, HttpServletRequest request, HttpServletResponse response) {
        //获取车辆列表
        String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
        carManage.setTenantId(tenantId);
        List<CarManage> carManageList = baseMapper.getCarManageList(carManage);
        if (carManageList == null) {
            carManageList = new ArrayList<>();
        }

        //导出
        List<String> stringList = new ArrayList<String>();
        String keyValue = "车辆照片:image,车牌号:code,车辆名称:name,用途:purpose,车主:carOwners,GPS设备:deviceCode,载重(吨):capacity,建档时间:createTime";

        String title = "车辆列表";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);
            ExcelTools.exportBankExcelV2(outputStream, keyValue, carManageList, ExcelConstant.XLS, title, stringList);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败");
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败");
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<Integer, String> importData(MultipartFile file) {
        Map<Integer, String> deviceErrorMap = new HashMap<>();
        List<CarManage> carManages = getImportData(getContentList(file), deviceErrorMap);
        if (carManages != null && carManages.size() > 0) {
            baseMapper.saveBatchCarManages(carManages);
        }
        return deviceErrorMap;
    }

    @Override
    public void getImportTemplateSpace(HttpServletRequest request, HttpServletResponse response) {
        String title = "车辆批量导入模板";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil
                    .getOutputStream(request, response, fileName);

            String keyValue = "车牌号(必填*):code,车辆名称(必填*):name,用途(必填*):purpose,车主:carOwners,GPS设备(必填*):deviceCode,载重(吨)(必填*):capacity";
            ExcelTools
                    .exportExcel(outputStream, keyValue, inits(), ExcelConstant.XLS,
                            title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            LOGGER.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常");
        } catch (Exception e) {
            LOGGER.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！");
        }
    }

    public List<HashMap<String, Object>> inits(){
        return Arrays.asList( new HashMap<String,Object>(){{
            put("code", "京A-888888");
            put("name","红旗H5");
            put("purpose","田间打药");
            put("carOwners","赵某某");
            put("deviceCode","VIR1632304685091");
            put("capacity","50.12");
        }});
    }

    private List<CarManage> getImportData(List<List<String>> contentList, Map<Integer, String> deviceErrorMap) {
        LinkappUser notNullCurrent = linkappUserContextProducer.getNotNullCurrent();
        String value;
        Date date = new Date();
        List<CarManage> devices = new ArrayList<>();
        CarManage carManage = null;
        for (int row = 1; row < contentList.size(); row++) {
            try {
                boolean loop = true;
                carManage = new CarManage();
                for (int i = 0; i < contentList.get(row).size() && loop; i++) {
                    value = StringUtils.isEmpty(contentList.get(row).get(i))
                            || StringUtils.isEmpty(contentList.get(row).get(i).trim())
                            ? null : contentList.get(row).get(i).trim();
                    switch (i) {
                        case 0:
                            if (null != value) {
                                //验证车牌号以及设备是否重复
                                QueryWrapper<CarManage> qw = new QueryWrapper<CarManage>();
                                qw.eq("tenant_id",notNullCurrent.getTenantId());
                                qw.eq("code",value);
                                Integer count = baseMapper.selectCount(qw);
                                if(count > 0){
                                    loop = false;
                                    deviceErrorMap.put(row, "第" + row + "行，车牌号重复");
                                }else {
                                    carManage.setCode(value);
                                }
                            } else {
                                deviceErrorMap.put(row, "第" + row + "行，车牌号不能为空");
                                loop = false;
                            }
                            break;
                        case 1:
                            if (null != value) {
                                carManage.setName(value);
                            } else {
                                deviceErrorMap.put(row, "第" + row + "行，车辆名称不能为空");
                                loop = false;
                            }
                            break;
                        case 2:
                            if (null != value) {
                                if ("田间打药".equals(value)) {
                                    carManage.setPurpose("1");
                                } else if ("粪便输送".equals(value)) {
                                    carManage.setPurpose("2");
                                } else if ("农村洒水".equals(value)) {
                                    carManage.setPurpose("3");
                                } else if ("田间撒肥".equals(value)) {
                                    carManage.setPurpose("4");
                                } else {
                                    deviceErrorMap.put(row, "第" + row + "行，车辆用途填写错误, 不支持此类型");
                                    loop = false;
                                }
                            } else {
                                deviceErrorMap.put(row, "第" + row + "行，车辆用途不能为空");
                                loop = false;
                            }
                            break;
                        case 3:
                            carManage.setCarOwners(value);
                            break;
                        case 4:
                            if (null != value) {
                                // 根据设备编号查询设备id
                                String deviceId = baseMapper.getDeviceIdByCode(value,notNullCurrent.getTenantId());
                                if (deviceId == null) {
                                    loop = false;
                                    deviceErrorMap.put(row, "第" + row + "行，车辆设备数据不存在");
                                    break;
                                }

                                QueryWrapper<CarManage> qw = new QueryWrapper<CarManage>();
                                qw.eq("tenant_id",notNullCurrent.getTenantId());
                                qw.eq("gps_id",deviceId);
                                Integer count = baseMapper.selectCount(qw);
                                if(count > 0){
                                    loop = false;
                                    deviceErrorMap.put(row, "第" + row + "行，车辆绑定设备重复");
                                }else {
                                    carManage.setGpsId(deviceId);
                                }
                            } else {
                                deviceErrorMap.put(row, "第" + row + "行，车辆设备不能为空");
                                loop = false;
                            }
                            break;
                        case 5:
                            if (null != value && YYSHDateUtil.match(RegularExpressionConstant.zhengShuPattern, value) && (new BigDecimal(value).compareTo(new BigDecimal(0.0))) > 0) {
                                carManage.setCapacity(new BigDecimal(value));
                            } else {
                                deviceErrorMap.put(row, "第" + row + "行，载重量不能为空且必须是大于0的数字");
                                loop = false;
                            }
                            break;
                        default:
                            break;
                    }
                }
                if (loop) {
                    carManage.setTenantId(notNullCurrent.getTenantId());
                    carManage.setModifier(notNullCurrent.getId()+"");
                    carManage.setCreator(notNullCurrent.getId()+"");
                    carManage.setModifyTime(date);
                    carManage.setCreateTime(date);
                    devices.add(carManage);
                }
            } catch (Exception e) {
                deviceErrorMap.put(row, "第" + row + "行" + e.getMessage());
                continue;
            }
        }
        return devices;
    }



    private List<List<String>> getContentList(MultipartFile file) {

        List<List<String>> contentList = ExcelReadUtil.getExcelInfo(file, 1, null, -1);

        //验证导入文件 是否使用了正确的模板，以及表格第一列是否缺失或多了字段
        Map<Integer, String> standardHeaderRow = new HashMap<>(6);

        String keyValue = "车牌号(必填*):code,车辆名称(必填*):name,用途(必填*):purpose,车主:carOwners,GPS设备(必填*):deviceCode,载重(吨)(必填*):capacity";
        List<String> keys = Arrays.asList(StringUtils.split(keyValue, ",")).stream().map(s -> s = s.substring(0, s.indexOf(":"))).collect(Collectors.toList());
        for (int i = 0; i < keys.size(); i++) {
            standardHeaderRow.put(i, keys.get(i));
        }

        StringUtils.split(",");
        //根据表头判断是否使用了正确的模板
        ExcelReadUtil.validateExeclTemplet(contentList, 0, standardHeaderRow);

        int[] requiredColumnIndexes = {0, 1, 2, 4, 5};

        int errorNum = ExcelReadUtil.validateRequiredFields(contentList, requiredColumnIndexes);
        if (errorNum != -1) {
            throw new RuntimeException("第" + (errorNum + 1) + "行,必填写列为空");
        }
        return contentList;
    }

}
